package com.bjh.components;

import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.CountDownLatch;

/**
 * 这是ZK操作的工具类
 */
@Slf4j
@Component
public class ZookUtil {

    @Resource
    private ZooKeeper zooKeeperClient;

    final CountDownLatch countDownLatch = new CountDownLatch(1);

    /**
     * 同步或者异步创建节点,都不支持子节点的递归创建,异步有一个callback函数
     * 参数:
     *      path:创建的路径
     *      data:存储的数据的byte[]
     *      acl:控制权限策略
     *          Ids.OPE_ACL_UNSAFE-->world:anyone:cdrwa
     *          CREATOR_ALL_ACL-->auth:user:password:cdrwa
     *      createMode:节点类型,是一个枚举
     *                  PERSISTENT:持久化节点
     *                  PERSISTENT_SEQUENTIAL:持久化顺序节点
     *                  EPHEMERAL:临时节点
     *                  EPHEMERAL_SEQUENTIAL:临时顺序节点
     */

    public void createNode(String path,String data){
//        final CountDownLatch countDownLatch = new CountDownLatch(1);
        try {
            //同步创建
            zooKeeperClient.create(path,data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            //异步创建
//            String ctx = "{'create':'success'}";
//            zooKeeperClient.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, new AsyncCallback.StringCallback() {
//                @Override
//                public void processResult(int i, String path, Object ctx, String name) {
//                    log.info("异步创建节点通知:{},{},{},{}",i,path,ctx,name);
//                    countDownLatch.countDown();
//                }
//            },ctx);
//            countDownLatch.await();
            log.info("创建节点成功=======");
        } catch (Exception e) {
            log.error("【创建持久化节点异常】{},{},{}",path,data,e);
        }
    }

    /**
     * 修改节点数据
     */
    public void updateData(String path,String data){
        try {
            //zk的数据版本是从0开始计数的。如果客户端传入的是-1，则表示zk服务器需要基于最新的数据进行更新。如果对zk的数据节点的更新操作没有原子性要求则可以使用-1.
            //version参数指定要更新的数据的版本, 如果version和真实的版本不同, 更新操作将失败. 指定version为-1则忽略版本检查
            Stat stat = zooKeeperClient.setData(path, data.getBytes(), 0);
            log.info("更新节点:{}",stat);
            //版本号不对 ->KeeperErrorCode = BadVersion for /cheng
            //也有异步方式
        } catch (Exception e) {
            log.error("【修改持久化节点异常】{},{},{}",path,data,e);
        }
    }

    /**
     * 删除节点
     */
    public void deleteNode(String path){
        try {
            //创建一个删除节点
            zooKeeperClient.create("/delete-node","123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
            //version参数指定要更新的数据的版本, 如果version和真实的版本不同, 更新操作将失败. 指定version为-1则忽略版本检查
            //同步方式
            //zkClient.delete(path,-1);
            //异步方式
            zooKeeperClient.delete("/delete-node", 0, new AsyncCallback.VoidCallback() {
                @Override
                public void processResult(int i, String path, Object ctx) {
                    countDownLatch.countDown();
                    log.info("节点删除成功回调:path:{},ctx:{}",path,ctx);
                }
            },"success");
            countDownLatch.await();
        } catch (Exception e) {
            log.error("【删除持久化节点异常】{},{}",path,e);
        }
    }

    /**
     * 获取节点数据
     */
    public String getNodeData(String path){
        //获取数据完之后 自动为state赋上值
        Stat stat=new Stat();
        String data = null;
        try {
            byte[] bytes=zooKeeperClient.getData(path,true,stat);
            data = new String(bytes);
            log.info("获取节点数据data:{},stat:{}",data,stat);
            return data;
        } catch (Exception e) {
            return data;
        }
    }


    /**
     * 权限操作
     * @throws NoSuchAlgorithmException
     * @throws KeeperException
     * @throws InterruptedException
     */
    public void acl() throws NoSuchAlgorithmException, KeeperException, InterruptedException {
        //自定义权限
//        List<ACL> acls = new ArrayList<>();
//        Id imooc1 = new Id("digest",getDigestUserPwd("imooc1:123456"));
//        Id imooc2 = new Id("digest",getDigestUserPwd("imooc2:123456"));
//        acls.add(new ACL(ZooDefs.Perms.ALL,imooc1));
//        acls.add(new ACL(ZooDefs.Perms.READ,imooc2));
//        acls.add(new ACL(ZooDefs.Perms.DELETE | ZooDefs.Perms.CREATE,imooc2));
//        zkClient.create("/aclimooc/testdigest","testdigest".getBytes(),acls,CreateMode.PERSISTENT);

        //注册用户必须通过addAuthInfo才能操作节点,参考命令addauth
        // zkClient.addAuthInfo("digest","imooc2:123456".getBytes());
        //zkClient.create("/aclimooc/testdigest/children","children-value".getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL,CreateMode.PERSISTENT);

        //设置值 没有修改权限 报错KeeperErrorCode = NoAuth for /aclimooc/testdigest
        zooKeeperClient.setData("/aclimooc/testdigest","123".getBytes(),-1);


    }


    private String getDigestUserPwd(String id) throws NoSuchAlgorithmException {
        return DigestAuthenticationProvider.generateDigest(id);
    }
}
